Creating Modern Card-Based Interfaces in Flutter
Card-based interfaces are a popular way to organize modern application screens into small, visually separated sections. In Flutter, the Card widget can be combined with widgets such as Column, Row, ListTile, Image, Icon, ElevatedButton, OutlinedButton, InkWell, GridView, and ListView to create professional interfaces.
Flutter's Material library provides Material Design components, and Material 3 is the default design language in current Flutter releases. Cards are intended for presenting related pieces of information in a contained surface. :contentReference[oaicite:0]{index=0}
1. What is a Card-Based Interface?
A card-based interface is a UI design in which information is divided into separate rectangular or rounded sections called cards.
Each card usually represents one independent piece of information or one specific action.
For example, an e-commerce application might use cards for:
- Products
- Product categories
- Offers
- Orders
- Customer information
A learning application might use cards for:
- Courses
- Lessons
- Assignments
- Progress information
- Instructor information
2. Why Use Card-Based Interfaces?
Cards make complex information easier to scan and organize.
- Separate unrelated content.
- Group related information.
- Improve visual hierarchy.
- Make interfaces easier to scan.
- Create reusable UI components.
- Provide clear areas for actions.
- Work well with lists and grids.
- Adapt easily to responsive layouts.
3. Basic Card Structure
A Flutter Card accepts a single child, but that child can contain many other widgets through a Row, Column, ListView, GridView, or another multi-child widget. Flutter's documentation describes Card as a Material surface for related information. :contentReference[oaicite:1]{index=1}
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Flutter Course',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'Learn Flutter development from basics to advanced concepts.',
),
],
),
),
)
4. Important Components of a Modern Card
A modern card can contain several UI elements.
| Component |
Purpose |
| Image |
Provides visual information. |
| Title |
Identifies the card content. |
| Subtitle |
Provides additional information. |
| Icon |
Communicates an action or category. |
| Badge |
Displays status or short information. |
| Price |
Displays product or service cost. |
| Button |
Provides an action. |
| Progress Indicator |
Shows completion or progress. |
| InkWell |
Makes a card respond to taps. |
5. Designing a Simple Modern Card
Card(
elevation: 3,
margin: const EdgeInsets.all(12),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Modern Flutter Card',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'This card contains related information in a clean layout.',
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {},
child: const Text('Learn More'),
),
],
),
),
)
6. Card with Rounded Corners
Rounded corners are commonly used in modern UI designs.
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: const Padding(
padding: EdgeInsets.all(20),
child: Text('Rounded Modern Card'),
),
)
Rounded corners can help create a softer visual appearance while maintaining a clear content boundary.
7. Card with Elevation
Elevation creates a visual separation between a Card and the surrounding surface. Flutter's Card documentation describes elevation as controlling the shadow effect. :contentReference[oaicite:2]{index=2}
Card(
elevation: 5,
child: const Padding(
padding: EdgeInsets.all(20),
child: Text('Elevated Card'),
),
)
Use elevation carefully. A modern interface usually benefits from subtle shadows rather than extremely heavy shadows.
8. Card with Image
Images are commonly placed at the top of cards for products, courses, articles, destinations, and other visual content.
Card(
clipBehavior: Clip.antiAlias,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
'https://picsum.photos/600/300',
width: double.infinity,
height: 200,
fit: BoxFit.cover,
),
const Padding(
padding: EdgeInsets.all(16),
child: Text(
'Beautiful Destination',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
)
9. Why Use clipBehavior?
When a card has rounded corners and contains an image, clipBehavior can ensure that the child content follows the Card's shape.
Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Image.network(
'https://picsum.photos/600/300',
height: 200,
width: double.infinity,
fit: BoxFit.cover,
),
)
10. Modern Product Card
Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
'https://picsum.photos/600/400',
height: 220,
width: double.infinity,
fit: BoxFit.cover,
),
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Wireless Headphones',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 6),
const Text(
'Premium wireless headphones with noise cancellation.',
),
const SizedBox(height: 12),
const Text(
'₹2,999',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 15),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () {},
child: const Text('Details'),
),
),
const SizedBox(width: 10),
Expanded(
child: ElevatedButton(
onPressed: () {},
child: const Text('Buy Now'),
),
),
],
),
],
),
),
],
),
)
11. Product Card with Rating
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Flutter Course',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Row(
children: [
...List.generate(
5,
(index) => const Icon(
Icons.star,
size: 20,
color: Colors.amber,
),
),
const SizedBox(width: 8),
const Text('4.8'),
],
),
const SizedBox(height: 10),
const Text(
'Learn Flutter development with practical projects.',
),
],
),
),
)
12. Course Card
Card(
clipBehavior: Clip.antiAlias,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
'https://picsum.photos/700/350',
width: double.infinity,
height: 180,
fit: BoxFit.cover,
),
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Flutter Development',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'Learn Dart, Flutter widgets, layouts, navigation, APIs, and application development.',
),
const SizedBox(height: 12),
Row(
children: [
const Icon(Icons.access_time, size: 18),
const SizedBox(width: 5),
const Text('40 Hours'),
const Spacer(),
ElevatedButton(
onPressed: () {},
child: const Text('Enroll'),
),
],
),
],
),
),
],
),
)
13. Profile Card
Card(
child: Padding(
padding: const EdgeInsets.all(18),
child: Row(
children: [
const CircleAvatar(
radius: 35,
child: Icon(Icons.person, size: 35),
),
const SizedBox(width: 15),
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'John Doe',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 5),
Text('Flutter Developer'),
SizedBox(height: 3),
Text('Mumbai, India'),
],
),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.more_vert),
),
],
),
),
)
14. Dashboard Statistic Cards
Card-based dashboards are useful for presenting important statistics in a compact format.
Row(
children: [
Expanded(
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const Icon(Icons.people),
const SizedBox(height: 8),
const Text(
'12,450',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const Text('Users'),
],
),
),
),
),
Expanded(
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const Icon(Icons.shopping_cart),
const SizedBox(height: 8),
const Text(
'3,240',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const Text('Orders'),
],
),
),
),
),
],
)
15. Modern Card with Badge
Badges can display statuses such as New, Popular, Active, Pending, or Sale.
Stack(
children: [
Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Flutter Masterclass',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'Complete Flutter development course.',
),
],
),
),
),
Positioned(
top: 10,
right: 10,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
),
child: const Text('Popular'),
),
),
],
)
16. Clickable Modern Card
Cards can be made interactive when the entire card represents an action. Flutter's Card documentation demonstrates using InkWell so that a card can act as one large touch target. :contentReference[oaicite:3]{index=3}
Card(
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () {
print('Card tapped');
},
child: const Padding(
padding: EdgeInsets.all(20),
child: Row(
children: [
Icon(Icons.article),
SizedBox(width: 15),
Expanded(
child: Text(
'Open Flutter article',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
Icon(Icons.arrow_forward_ios),
],
),
),
),
)
InkWell provides Material touch feedback when the user interacts with the card. It requires a Material ancestor for its ink effects. :contentReference[oaicite:4]{index=4}
17. Card with InkWell and Image
Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
),
child: InkWell(
onTap: () {
print('Course selected');
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
'https://picsum.photos/600/300',
height: 180,
width: double.infinity,
fit: BoxFit.cover,
),
const Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Flutter Development',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 6),
Text('Tap to view course details.'),
],
),
),
],
),
),
)
18. Card with ListTile
ListTile is especially useful inside cards for compact rows containing leading icons, titles, subtitles, and trailing actions.
Card(
child: ListTile(
leading: const CircleAvatar(
child: Icon(Icons.person),
),
title: const Text('John Doe'),
subtitle: const Text('Flutter Developer'),
trailing: IconButton(
onPressed: () {},
icon: const Icon(Icons.arrow_forward_ios),
),
),
)
19. Modern List Card
Card(
margin: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: ListTile(
contentPadding: const EdgeInsets.all(16),
leading: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
'https://picsum.photos/100/100',
width: 70,
height: 70,
fit: BoxFit.cover,
),
),
title: const Text(
'Flutter Course',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
subtitle: const Padding(
padding: EdgeInsets.only(top: 6),
child: Text(
'Learn Flutter development through practical projects.',
),
),
trailing: const Icon(Icons.arrow_forward_ios),
),
)
20. Cards in ListView
ListView(
padding: const EdgeInsets.all(16),
children: [
Card(
child: ListTile(
leading: const Icon(Icons.school),
title: const Text('Flutter'),
subtitle: const Text('Mobile app development'),
),
),
Card(
child: ListTile(
leading: const Icon(Icons.code),
title: const Text('Dart'),
subtitle: const Text('Programming language'),
),
),
Card(
child: ListTile(
leading: const Icon(Icons.cloud),
title: const Text('Firebase'),
subtitle: const Text('Backend services'),
),
),
],
)
21. Cards in GridView
Grid layouts are useful when multiple cards need to be displayed in rows and columns.
GridView.count(
padding: const EdgeInsets.all(16),
crossAxisCount: 2,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
children: [
Card(
child: const Center(
child: Text('Flutter'),
),
),
Card(
child: const Center(
child: Text('Dart'),
),
),
Card(
child: const Center(
child: Text('Firebase'),
),
),
Card(
child: const Center(
child: Text('API'),
),
),
],
)
22. Responsive Card Grid
A modern card interface should adapt to different screen widths. Flutter's layout system provides tools such as LayoutBuilder for building layouts according to available constraints. :contentReference[oaicite:5]{index=5}
LayoutBuilder(
builder: (context, constraints) {
int columns;
if (constraints.maxWidth >= 1000) {
columns = 4;
} else if (constraints.maxWidth >= 700) {
columns = 3;
} else if (constraints.maxWidth >= 500) {
columns = 2;
} else {
columns = 1;
}
return GridView.builder(
padding: const EdgeInsets.all(16),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 0.8,
),
itemCount: 8,
itemBuilder: (context, index) {
return Card(
child: Center(
child: Text('Card ${index + 1}'),
),
);
},
);
},
)
23. Card Aspect Ratio
When cards are displayed in a GridView, childAspectRatio can help maintain consistent proportions.
GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 0.8,
),
itemCount: 10,
itemBuilder: (context, index) {
return Card(
child: Center(
child: Text('Product ${index + 1}'),
),
);
},
)
24. Modern Card with Progress
Card(
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Flutter Course',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
const Text('Course Progress'),
const SizedBox(height: 8),
LinearProgressIndicator(
value: 0.65,
borderRadius: BorderRadius.circular(10),
),
const SizedBox(height: 8),
const Text('65% completed'),
],
),
),
)
25. Modern Card with Status
Card(
child: Padding(
padding: const EdgeInsets.all(18),
child: Row(
children: [
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Order #1024',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 5),
Text('2 products'),
],
),
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
),
child: const Text('Delivered'),
),
],
),
),
)
26. Material 3 Card Variants
Material 3 provides three Card visual variants in Flutter:
- Card: Elevated card.
- Card.filled: Filled card.
- Card.outlined: Outlined card.
Flutter's Card API documents these three variants for Material 3. :contentReference[oaicite:6]{index=6}
Elevated Card
Card(
child: const Padding(
padding: EdgeInsets.all(20),
child: Text('Elevated Card'),
),
)
Filled Card
Card.filled(
child: const Padding(
padding: EdgeInsets.all(20),
child: Text('Filled Card'),
),
)
Outlined Card
Card.outlined(
child: const Padding(
padding: EdgeInsets.all(20),
child: Text('Outlined Card'),
),
)
27. Using Material 3 Theme
Material 3 has been the default design language in Flutter since Flutter 3.16. It can still be explicitly enabled for clarity in examples. :contentReference[oaicite:7]{index=7}
MaterialApp(
theme: ThemeData(
useMaterial3: true,
),
home: const HomePage(),
)
28. Creating a Modern Color Scheme
Material 3 provides a ColorScheme-based approach for application colors. Flutter documentation recommends using ColorScheme.fromSeed to generate a coordinated color scheme. :contentReference[oaicite:8]{index=8}
MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.indigo,
),
),
home: const HomePage(),
)
This helps maintain consistent colors across cards, buttons, app bars, dialogs, and other Material components.
29. CardThemeData
CardThemeData defines default property values for descendant Card widgets. It can be supplied through ThemeData.cardTheme. Properties include card color, elevation, margin, shape, shadow color, surface tint color, and clipping behavior. :contentReference[oaicite:9]{index=9}
MaterialApp(
theme: ThemeData(
useMaterial3: true,
cardTheme: CardThemeData(
elevation: 3,
margin: const EdgeInsets.all(10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
home: const HomePage(),
)
30. Creating a Reusable Card Widget
Reusable widgets help avoid repeating the same card structure throughout an application.
class CourseCard extends StatelessWidget {
final String title;
final String description;
final VoidCallback onPressed;
const CourseCard({
super.key,
required this.title,
required this.description,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
return Card(
clipBehavior: Clip.antiAlias,
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(description),
const SizedBox(height: 15),
ElevatedButton(
onPressed: onPressed,
child: const Text('View Course'),
),
],
),
),
);
}
}
Using the Reusable Card
CourseCard(
title: 'Flutter Development',
description: 'Learn Flutter from beginner to advanced level.',
onPressed: () {
print('Course selected');
},
)
31. Creating a Reusable Product Card
class ProductCard extends StatelessWidget {
final String name;
final String price;
final String imageUrl;
const ProductCard({
super.key,
required this.name,
required this.price,
required this.imageUrl,
});
@override
Widget build(BuildContext context) {
return Card(
clipBehavior: Clip.antiAlias,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
imageUrl,
height: 180,
width: double.infinity,
fit: BoxFit.cover,
),
Padding(
padding: const EdgeInsets.all(14),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 6),
Text(
price,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
child: const Text('Add to Cart'),
),
),
],
),
),
],
),
);
}
}
32. Modern Card with Actions
Card(
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Flutter Development',
style: TextStyle(
fontSize: 21,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'Build beautiful cross-platform applications.',
),
const SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {},
child: const Text('Details'),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: () {},
child: const Text('Enroll'),
),
],
),
],
),
),
)
33. Modern Card with Icon Header
Card(
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
),
child: const Icon(
Icons.flutter_dash,
size: 30,
),
),
const SizedBox(width: 12),
const Expanded(
child: Text(
'Flutter Development',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
const SizedBox(height: 15),
const Text(
'Learn widgets, layouts, navigation, state management, APIs, and more.',
),
],
),
),
)
34. Card-Based Dashboard Layout
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
children: [
Expanded(
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const Icon(Icons.people),
const SizedBox(height: 8),
const Text(
'12,450',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const Text('Users'),
],
),
),
),
),
Expanded(
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const Icon(Icons.shopping_cart),
const SizedBox(height: 8),
const Text(
'3,240',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const Text('Orders'),
],
),
),
),
),
],
),
Card(
child: ListTile(
leading: const Icon(Icons.attach_money),
title: const Text('Revenue'),
subtitle: const Text('₹8,45,000'),
trailing: const Icon(Icons.trending_up),
),
),
],
),
)
35. Card Layout with Spacing
Spacing is important for modern card interfaces. Use widgets such as SizedBox, Padding, and margin to create visual separation.
Column(
children: [
Card(
margin: const EdgeInsets.only(bottom: 12),
child: const Padding(
padding: EdgeInsets.all(18),
child: Text('First Card'),
),
),
Card(
margin: const EdgeInsets.only(bottom: 12),
child: const Padding(
padding: EdgeInsets.all(18),
child: Text('Second Card'),
),
),
Card(
child: const Padding(
padding: EdgeInsets.all(18),
child: Text('Third Card'),
),
),
],
)
36. Card-Based News Interface
Card(
clipBehavior: Clip.antiAlias,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
'https://picsum.photos/700/350',
width: double.infinity,
height: 200,
fit: BoxFit.cover,
),
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Flutter Development News',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'Learn about modern Flutter application development.',
),
const SizedBox(height: 12),
TextButton(
onPressed: () {},
child: const Text('Read More'),
),
],
),
),
],
),
)
37. Card-Based Settings Interface
Card(
child: Column(
children: [
ListTile(
leading: const Icon(Icons.person),
title: const Text('Account'),
trailing: const Icon(Icons.arrow_forward_ios),
onTap: () {},
),
const Divider(height: 1),
ListTile(
leading: const Icon(Icons.notifications),
title: const Text('Notifications'),
trailing: const Icon(Icons.arrow_forward_ios),
onTap: () {},
),
const Divider(height: 1),
ListTile(
leading: const Icon(Icons.security),
title: const Text('Security'),
trailing: const Icon(Icons.arrow_forward_ios),
onTap: () {},
),
],
),
)
38. Dark Theme Card Design
MaterialApp(
theme: ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.indigo,
brightness: Brightness.dark,
),
),
home: const HomePage(),
)
Using ThemeData allows cards and other Material components to automatically participate in the application's overall theme. Flutter's theme system is designed to share colors and typography throughout an application. :contentReference[oaicite:10]{index=10}
39. Light and Dark Theme Support
MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
),
darkTheme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
),
themeMode: ThemeMode.system,
home: const HomePage(),
)
40. Modern Card Design Principles
1. Clear Visual Hierarchy
The title should normally be more prominent than supporting information.
2. Consistent Spacing
Use consistent padding and spacing across cards.
3. Limited Content
Keep the content focused on one subject or task.
4. Clear Actions
Buttons and interactive elements should have understandable labels.
5. Consistent Shapes
Use consistent corner radii throughout related screens.
6. Controlled Elevation
Use elevation to communicate hierarchy instead of adding large shadows everywhere.
7. Responsive Layout
Cards should adapt to available screen width.
41. Card Accessibility
Modern card interfaces should also be accessible.
- Use meaningful text labels.
- Do not communicate important information only through color.
- Ensure sufficient contrast.
- Provide meaningful semantic labels when required.
- Make interactive areas large enough to use comfortably.
- Do not make small icons the only way to perform important actions.
- Use clear button labels such as "View Details" instead of ambiguous labels.
42. Card Performance Tips
- Use ListView.builder for large scrolling lists.
- Use GridView.builder for large card grids.
- Avoid unnecessarily rebuilding expensive card widgets.
- Use const constructors where possible.
- Optimize large images.
- Use appropriate image dimensions and caching strategies.
- Keep complex widget trees organized into reusable widgets.
Example with ListView.builder
ListView.builder(
itemCount: 100,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 6,
),
child: ListTile(
title: Text('Course ${index + 1}'),
subtitle: const Text(
'Flutter development course',
),
),
);
},
)
43. Complete Modern Card-Based Application Example
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.indigo,
),
cardTheme: CardThemeData(
elevation: 2,
margin: const EdgeInsets.all(8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
),
),
),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Modern Cards'),
),
body: GridView.builder(
padding: const EdgeInsets.all(16),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 0.72,
),
itemCount: 6,
itemBuilder: (context, index) {
return Card(
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () {
print('Card ${index + 1} selected');
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
'https://picsum.photos/400/250?random=$index',
width: double.infinity,
height: 140,
fit: BoxFit.cover,
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'Course ${index + 1}',
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 6),
const Expanded(
child: Text(
'Learn modern application development with Flutter.',
),
),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
child: const Text('View Course'),
),
),
],
),
),
),
],
),
),
);
},
),
);
}
}
44. Card Design Checklist
| Question |
Recommended Approach |
| Does the card represent one logical item? |
Keep related content together. |
| Is the title easy to identify? |
Use appropriate typography hierarchy. |
| Is the card interactive? |
Use InkWell or clear action buttons. |
| Is there too much content? |
Reduce or divide the information. |
| Does the card work on mobile? |
Use responsive layouts. |
| Are cards visually consistent? |
Use reusable widgets and CardThemeData. |
| Are shadows too strong? |
Use subtle elevation. |
| Are actions clear? |
Use meaningful button labels. |
45. Common Mistakes
Mistake 1: Putting Everything in Cards
Cards should help organize information, not wrap every individual widget unnecessarily.
Mistake 2: Excessive Elevation
Very large shadows can make the UI look cluttered.
Mistake 3: Inconsistent Card Design
Using different corner radii, padding, and typography for similar cards can make the application look inconsistent.
Mistake 4: Too Many Buttons
A card should have clear and focused actions rather than many competing buttons.
Mistake 5: Poor Mobile Layout
A card that looks good on a desktop-sized screen may become cramped on a phone. Use responsive layouts and appropriate constraints.
Mistake 6: Unnecessary Nested Cards
Too many cards inside cards can make the hierarchy confusing. Use other layout widgets when a separate surface is not required.
46. Interview Questions
- What is a card-based interface?
- What is the Flutter Card widget?
- Why are cards used in modern UI design?
- How can you add padding inside a Card?
- How can you change Card elevation?
- How can you create rounded Card corners?
- What is the purpose of clipBehavior?
- How can you make an entire Card clickable?
- What is the purpose of InkWell?
- How can Cards be displayed in a ListView?
- How can Cards be displayed in a GridView?
- How can you create responsive card layouts?
- What is CardThemeData?
- How can CardThemeData be applied globally?
- What are Card.filled and Card.outlined?
- How does Material 3 affect Cards?
- How can you create reusable Card widgets?
- How can you optimize large lists of Cards?
- What are important accessibility considerations for cards?
- What are common mistakes when designing card-based interfaces?
47. Practice Exercises
- Create a modern product card with image, title, price, rating, and Buy Now button.
- Create a course card with course image, title, description, duration, and Enroll button.
- Create a profile card with avatar, name, profession, and View Profile button.
- Create a dashboard with four statistic cards.
- Create a clickable card using InkWell.
- Create a responsive GridView containing product cards.
- Create elevated, filled, and outlined Material 3 cards.
- Create a reusable ProductCard widget.
- Create a card containing a progress indicator.
- Create a news application screen using multiple article cards.
- Create a settings screen using cards and ListTile.
- Create a dark-theme card interface.
- Create a CardThemeData configuration for a complete application.
- Create a responsive layout that shows one card on mobile and multiple cards on larger screens.
48. Key Takeaways
- Card-based interfaces divide information into organized visual sections.
- Flutter's Card widget is designed for grouping related information.
- Cards can contain images, text, icons, buttons, ListTiles, progress indicators, and other widgets.
- Use padding and spacing to create clean card layouts.
- Use elevation carefully to create visual hierarchy.
- Use rounded corners consistently.
- Use InkWell when an entire card should behave as a touch target.
- Use ListView for vertically scrolling cards.
- Use GridView for grid-based card layouts.
- Use LayoutBuilder or other responsive layout techniques to adapt cards to different screen widths.
- Material 3 provides elevated, filled, and outlined Card variants. :contentReference[oaicite:11]{index=11}
- CardThemeData can provide consistent styling across descendant Card widgets. :contentReference[oaicite:12]{index=12}
- Reusable card widgets make large Flutter applications easier to maintain.
- Modern card design should prioritize hierarchy, consistency, responsiveness, accessibility, and usability.
49. Learning Resources
Official Flutter Documentation